using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using needle.UI.Controls.Flat.Windows.Docking;
using needle.UI.Controls.Flat.Windows.Forms.Helpers;

namespace needle.UI.Controls.Flat.Windows.Forms
{
	#region IResizeBar

	public interface IResizeSource
    {
        bool CanResize(ResizeBar bar);
        bool StartResizeOperation(ResizeBar bar, ref Rectangle screenBoundary);
        void EndResizeOperation(ResizeBar bar, int delta);
        Color ResizeBarColor { get; }
        int ResizeBarVector { get; }
        Color BackgroundColor { get; }
    }

	#endregion 

	#region ResizeBar

	[ToolboxItem(false)]
    public class ResizeBar : Control
    {
        protected const int mideLength = 4;
        protected const int mplainLength = 6;

        protected Direction mdirection;
        protected bool mresizing;
        protected Point mpointStart;
        protected Point mpointCurrent;
        protected Rectangle mboundary;
        protected IResizeSource mresizeSource;

		#region Constructors

		public ResizeBar(Direction direction, IResizeSource resizeSource)
        {
            mdirection = direction;
            mresizing = false;
            mresizeSource = resizeSource;

			this.BackColor = mresizeSource.ResizeBarColor;
			this.ForeColor = SystemColors.ControlText;

            UpdateStyle();
        }

		#endregion

		#region Virtuals

		public virtual void PropogateNameValue(PropogateName name, object value)
		{
			if (name == PropogateName.ResizeBarVector)
				this.Length = (int)value;

			if (name == PropogateName.ResizeBarColor)
			{
				this.BackColor = (Color)value;
				Invalidate();
			}
		}
        
		protected void UpdateStyle()
		{
			int vector = this.Length;

			if (mdirection == Direction.Vertical)
				this.Height = vector;
			else
				this.Width = vector;

			Invalidate();
		}

		protected bool StartResizeOperation(MouseEventArgs e)
		{
			if (mresizeSource != null)
			{
				if (mresizeSource.CanResize(this))
				{
					if (mresizeSource.StartResizeOperation(this, ref mboundary))
					{
						mpointStart = PointToScreen(new Point(e.X, e.Y));

						mpointCurrent = mpointStart;

						DrawResizeIndicator(mpointCurrent);

						return true;
					}
				}
			}

			return false;
		}

		protected void EndResizeOperation(MouseEventArgs e)
		{
			if (mresizeSource != null)
			{
				DrawResizeIndicator(mpointCurrent);

				Point newCurrent = PointToScreen(new Point(e.X, e.Y));

				ApplyBoundaryToPoint(ref newCurrent);

				Point delta = new Point(newCurrent.X - mpointStart.X, 
					newCurrent.Y - mpointStart.Y);

				if (mdirection == Direction.Horizontal)
					mresizeSource.EndResizeOperation(this, delta.X);
				else
					mresizeSource.EndResizeOperation(this, delta.Y);
			}

			mresizing = false;
		}

		protected void UpdateResizePosition(MouseEventArgs e)
		{
			Point newCurrent = PointToScreen(new Point(e.X, e.Y));

			ApplyBoundaryToPoint(ref newCurrent);

			if (newCurrent != mpointCurrent)
			{
				DrawResizeIndicator(mpointCurrent);

				mpointCurrent = newCurrent;

				DrawResizeIndicator(mpointCurrent);
			}
		}
	
		protected void ApplyBoundaryToPoint(ref Point newCurrent)
		{
			Point delta = new Point(newCurrent.X - mpointStart.X, 
				newCurrent.Y - mpointStart.Y);
			
			Rectangle client = RectangleToScreen(this.ClientRectangle);

			if (mdirection == Direction.Horizontal)
			{
				client.Offset(delta.X, 0);

				if (client.X < mboundary.X)
					newCurrent.X += mboundary.X - client.X;
				
				if (client.Right > mboundary.Right)
					newCurrent.X -= client.Right - mboundary.Right;
			}
			else
			{
				client.Offset(0, delta.Y);

				if (client.Y < mboundary.Y)
					newCurrent.Y += mboundary.Y - client.Y;
				
				if (client.Bottom > mboundary.Bottom)
					newCurrent.Y -= client.Bottom - mboundary.Bottom;
			}		
		}

		protected void DrawResizeIndicator(Point screenPosition)
		{
			Point delta = new Point(screenPosition.X - mpointStart.X, 
				screenPosition.Y - mpointStart.Y);

			Rectangle client = RectangleToScreen(this.ClientRectangle);

			if (mdirection == Direction.Horizontal)
				client.Offset(delta.X, 0);
			else
				client.Offset(0, delta.Y);

			GraphicsUtils.DrawDragRectangle(client, 0);
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			if (mresizing)
			{
				EndResizeOperation(e);
			}
			else
			{
				mresizing = StartResizeOperation(e);
			}

			base.OnMouseDown(e);
		}

		protected override void OnMouseUp(MouseEventArgs e)
		{
			if (mresizing)
			{
				EndResizeOperation(e);
			}

			base.OnMouseUp(e);
		}

		protected override void OnMouseMove(MouseEventArgs e)
		{
			if ((mresizeSource != null) && (mresizeSource.CanResize(this)))
			{
				if (mdirection == Direction.Vertical)
					this.Cursor = Cursors.SizeNS;
				else
					this.Cursor = Cursors.SizeWE;
			}
			else
				this.Cursor = Cursors.Arrow;

			if (mresizing)
			{
				UpdateResizePosition(e);
			}

			base.OnMouseMove(e);
		}

		#endregion

		#region Overrides

		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);
		}

		#endregion

		#region Properties

		public Direction Direction
		{
			get { return mdirection; }

			set
			{
				if (mdirection != value)
				{
					mdirection = value;
					UpdateStyle();
				}
			}
		}

		public int Length
		{
			get
			{
				int vector = mresizeSource.ResizeBarVector;
                
				if (vector == -1)
				{
					//if (mstyle == VisualStyle.IDE)
						vector = mideLength;
					//else 
					//	vector = mplainLength;
				}
               
				return vector;
			}
            
			set
			{
				if (value != this.Length)
				{
					UpdateStyle();
				}
			}
		}

		#endregion
    }

	#endregion
    
	#region ResizeAutoBar

	[ToolboxItem(false)]
    public class ResizeAutoBar : ResizeBar
    {
		#region Constructors

		public ResizeAutoBar(Direction direction, IResizeSource resizeSource)
            : base(direction, resizeSource) 
        {
        }    

		#endregion
            
		#region Overrides

		protected override void OnPaint(PaintEventArgs e)
        {
            Color backColor = this.BackColor;
        
            switch(this.Dock)
            {
                case DockStyle.Right:
                    using(Pen penD = new Pen(ControlPaint.Dark(backColor)),
                              penDD = new Pen(ControlPaint.DarkDark(backColor)))
                    {
                        e.Graphics.DrawLine(penD, this.Width - 2, 0, this.Width - 2, this.Height);
                        e.Graphics.DrawLine(penDD, this.Width - 1, 0, this.Width - 1, this.Height);
                    }
                    break;
                case DockStyle.Left:
                    using(Pen penLL = new Pen(ControlPaint.LightLight(backColor)))
                        e.Graphics.DrawLine(penLL, 1, 0, 1, this.Height);
                    break;
                case DockStyle.Bottom:
                    using(Pen penD = new Pen(ControlPaint.Dark(backColor)),
                              penDD = new Pen(ControlPaint.DarkDark(backColor)))
                    {
                        e.Graphics.DrawLine(penD, 0, this.Height - 2, this.Width, this.Height - 2);
                        e.Graphics.DrawLine(penDD, 0, this.Height - 1, this.Width, this.Height - 1);
                    }
                    break;
                case DockStyle.Top:
                    using(Pen penLL = new Pen(ControlPaint.LightLight(backColor)))
                        e.Graphics.DrawLine(penLL, 0, 1, this.Width, 1);
                    break;
            }
        }

		#endregion
    }

	#endregion
}